//--------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include <avr/io.h>
#include <avr/interrupt.h>

#include "dkbasic.h"
#include "dkfile_twi.h"
#include "dkstring.h"
#include "dkterm.h"
#include "dkexpression.h"


//--------------------------------------------------------------------

struct _dkdeviceio twideviceio =
{
	dktwi_open, 
	dktwi_close, 
	dktwi_read_byte, 
	dktwi_write_byte, 
	dktwi_read_bytes, 
	dktwi_write_bytes, 
	dktwi_seek, 
	dktwi_pos,
	dktwi_eof,
	dktwi_error
};


//--------------------------------------------------------------------

struct _dk_twi dktwi[1];


//--------------------------------------------------------------------
// parse filename for port #, speed, etc
//OPEN "TWI[n]:" AS [#]filenum [LEN=number]
int dktwi_open( DKFILE *stream )
{
	char t[MAX_TOKEN_LENGTH];					// used for token parsing with dkgettoken()
	dkexpression *e;
	char *filename;
	struct _dk_twi twiconfig;
	

	// fill in deviceinfo with defaults then update it with values from filenaem
	filename = stream->filename;
	filename += 3;								// skip past "TWI"

	filename = dkgettoken( filename, t );		// get [n] as token

	if( isdigit( *t ) )
		twiconfig.portnum = atoi( t );			// port #
	else
		return 1;								// error in filename (no port #)


	filename = dkgettoken( filename, t );		// get : as token
		
	if( (*t) != ':' )
		return 1;								// error in filename! (or filename done?)


	e = expression( filename );					// e = next expression (device address)
	filename = expstr;
	if( !e )
		return 1;								// error: missing operand

	dkexptoint( e );							// use (*t) address token
		
	if( e->type != DKVAR_INTEGER )
	{
		dkexpfree(e);
		return 1;							// error: type mismatch
	}
	twiconfig.address = ((uint16_t *)e->data)[0];
	dkexpfree(e);


	filename = dkgettoken( filename, t );	// get , as token
	if( (*t) && ( (*t) != ',' ) )
		return 1;							// error in filename (or filename done)



											// init TWI

//	dkuart0_rx_buffer;						// dynamically create rx buffer? 
											// (currently is static - must be 128 bytes for each buffer)


	switch( twiconfig.portnum )
	{
		case 0:								// init TWI0
			dktwi[0].portnum = twiconfig.portnum;
			dktwi[0].address = twiconfig.address;

			stream->info = &dktwi[0];

											// any hardware init to be done for TWI?
											// set DDR/PORT?
			break;
	}
	
	
	return 0;
}

//--------------------------------------------------------------------
int dktwi_close( void *deviceinfo )
{
//stop UART - disable RX interrupt
// destroy rx buffer?

	switch( ((struct _dk_twi *)deviceinfo)->portnum )
	{
		case 0:								// stop TWI0
//			UCSR0B = (0<<TXEN0) | (0<<RXEN0) | (0<<RXCIE0);
			break;
	}


	return 0;
}

//--------------------------------------------------------------------
int dktwi_read_byte(void *deviceinfo)
{
	return 0;
}
//--------------------------------------------------------------------
int dktwi_write_byte(void *deviceinfo, int c)
{
	switch( ((struct _dk_twi *)deviceinfo)->portnum )
	{
		case 0:								// send byte out TWI0
//			while( ! (UCSR0A & (1<<UDRE0)) )
//				;
//			UDR0 = c;
			break;
	}			

	return c;
}
//--------------------------------------------------------------------
int dktwi_read_bytes(void *deviceinfo, int n, void *ptr)
{
	int i;


//	printf_P(PSTR("|%d|a"), ((struct _dk_twi *)deviceinfo)->address);

	DDRD &= 0xFC;				// set PD0/PD1 as input with pullup enabled
	PORTD |= 0x03;

	TWBR = 100;


	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);		// send START condition
	
	while( !( TWCR&(1<<TWINT) ) )					// wait for TWINT flag to be set indicating START condition has been transmitted
	{
		if( io_ctrl_char==3)
			return -1;
	}

	
//	if( (TWSR&0xF8) != START )						// check value of TWI status register
//			;		// error();


//	printf_P(PSTR("b"));

	TWDR = ( ((struct _dk_twi *)deviceinfo)->address <<1 ) | 1;		// send SLA+R
	TWCR = (1<<TWINT) | (1<<TWEN);				// clear twint bit to start next rx

	while( !( TWCR&(1<<TWINT) ) )					// wait for TWINT flag to be set indicating START condition has been transmitted
	{
		if( io_ctrl_char==3)
			return -1;
	}

//	if( (TWSR&0xF8)!= MR_SLA_ACK )
//		;	// error();	


	for( i=0; i<n; i++ )
	{
//		printf_P(PSTR("c"));

		TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);				// clear twint bit to start next rx

		while( !( TWCR&(1<<TWINT) ) )					// wait for TWINT flag to be set indicating START condition has been transmitted
		{
			if( io_ctrl_char==3)
				return -1;
		}

//		if( (TWSR&0xF8) != MT_DATA_ACK )
//			;	// error();		

		((uint8_t *)ptr)[i] = TWDR;					// store received byte at ptr[i]				
	}


//	printf_P(PSTR("d"));

	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);			// transmit STOP
								


	return n;
}
//--------------------------------------------------------------------
int dktwi_write_bytes(void *deviceinfo, int n, void *ptr)
{
	switch( ((struct _dk_twi *)deviceinfo)->portnum )
	{
		case 0:								// send byte out TWI0
//			while( ! (UCSR0A & (1<<UDRE0)) )
//				;
//			UDR0 = c;
			break;
	}			

	return n;
}
//--------------------------------------------------------------------
int dktwi_seek(void *deviceinfo, off_t offset, int whence)
{
	return 0;
}
//--------------------------------------------------------------------
fpos_t dktwi_pos(void *deviceinfo)
{		// for COM ports, pos() returns # of bytes waiting in rx buffer
//	return abs( (* ((struct _dk_twi *)deviceinfo)->rx_wr_ptr ) - (* ((struct _dk_twi *)deviceinfo)->rx_rd_ptr ) );
	return 0;
}
//--------------------------------------------------------------------
int dktwi_eof(void *deviceinfo)
{
//	if( (* ((struct _dk_twi *)deviceinfo)->rx_wr_ptr ) != (* ((struct _dk_twi *)deviceinfo)->rx_rd_ptr ) ) 
//		return 0;

	return -1;
}
//--------------------------------------------------------------------
int dktwi_error(void *deviceinfo)
{
	return 0;
}

//--------------------------------------------------------------------
